home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / m68k / signal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  11.9 KB  |  418 lines

  1. /*
  2.  *  linux/kernel/signal.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  * This file is subject to the terms and conditions of the GNU General Public
  7.  * License.  See the file README.legal in the main directory of this archive
  8.  * for more details.
  9.  */
  10.  
  11. /*
  12.  * 680x0 support by Hamish Macdonald
  13.  */
  14.  
  15. #include <asm/system.h>
  16. #include <asm/segment.h>
  17.  
  18. #include <linux/sched.h>
  19. #include <linux/kernel.h>
  20. #include <linux/traps.h>
  21. #include <linux/signal.h>
  22. #include <linux/errno.h>
  23. #include <linux/wait.h>
  24. #include <linux/ptrace.h>
  25. #include <linux/unistd.h>
  26.  
  27. #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
  28.  
  29. #define _S(nr) (1<<((nr)-1))
  30. #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  31.  
  32. extern int core_dump(long signr,struct pt_regs * regs);
  33. asmlinkage int sys_wait4(pid_t pid,unsigned long * stat_addr, int options,
  34.              struct rusage *ru);
  35.  
  36. struct sigcontext {
  37.     unsigned long  sc_mask;     /* old sigmask */
  38.     unsigned long  sc_usp;        /* old user stack pointer */
  39.     unsigned long  sc_d0;
  40.     unsigned long  sc_d1;
  41.     unsigned long  sc_a0;
  42.     unsigned long  sc_a1;
  43.     unsigned short sc_sr;
  44.     unsigned long  sc_pc;
  45.     unsigned short sc_formatvec;
  46. };
  47.  
  48. asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
  49.  
  50. /*
  51.  * This sets regs->usp even though we don't actually use sigstacks yet..
  52.  */
  53. asmlinkage int sys_sigreturn(unsigned long __unused)
  54. {
  55.     struct sigcontext context;
  56.     struct frame * regs;
  57.     int fsize = 0;
  58.     int formatvec = 0;
  59.     unsigned long fp;
  60.  
  61.     /* get stack frame pointer */
  62.     regs = (struct frame *) &__unused;
  63.  
  64.     /* get previous context (including pointer to possible extra junk) */
  65.     memcpy_fromfs(&context,(void *) regs->usp, sizeof(context));
  66.     fp = regs->usp + sizeof (context);
  67.  
  68.     /* restore signal mask */
  69.     current->blocked = context.sc_mask & _BLOCKABLE;
  70.  
  71.     /* restore passed registers */
  72.     regs->d0 = context.sc_d0;
  73.     regs->regs[0] = context.sc_d1;
  74.     regs->regs[7] = context.sc_a0;
  75.     regs->regs[8] = context.sc_a1;
  76.     regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
  77.     regs->pc = context.sc_pc;
  78.     regs->usp = context.sc_usp;
  79.     formatvec = context.sc_formatvec;
  80.     regs->format = formatvec >> 12;
  81.     regs->vector = formatvec & 0xfff;
  82.  
  83.     switch (regs->format) {
  84.         case 0x0:
  85.         fsize = 0;
  86.         break;
  87.         case 0x2:
  88.         fsize = sizeof(regs->un.fmt2);
  89.         break;
  90.         case 0x9:
  91.         fsize = sizeof (regs->un.fmt9);
  92.         break;
  93.         case 0xA:
  94.         fsize = sizeof (regs->un.fmta);
  95.         break;
  96.         case 0xB:
  97.         fsize = sizeof (regs->un.fmtb);
  98.         break;
  99.         default:
  100.         /*
  101.          * user process trying to return with wierd frame format
  102.          * SIGILL the sucker.
  103.          */
  104.         send_sig (SIGILL, current, 1);
  105.         break;
  106.     }
  107.  
  108.     /* OK.    Make room on the supervisor stack for the extra junk,
  109.      * if necessary.
  110.      */
  111.  
  112.     if (fsize) {
  113.         __asm__ __volatile__
  114.             ("movel %0,a0\n\t"
  115.              "subl %2,a0\n\t"     /* make room on stack */
  116.              "movel a0,sp\n\t"    /* set stack pointer */
  117.              "1: movew %0@+,a0@+\n\t"
  118.              "   dbra %3,1b\n\t"
  119.              "movel sp,a0\n\t"
  120.              "addl  %4,a0\n\t"    /* add offset of fmt stuff */
  121.              "lsrl  #1,%2\n\t"
  122.              "subql #1,%2\n\t"
  123.              "2: movesw %5@+,d0\n\t"
  124.              "   movew d0,a0@+\n\t"
  125.              "   dbra %2,2b\n\t"
  126.              "bra _ret_from_exception"
  127.              : "=a" (regs)
  128.              : "0" (regs), "d" (fsize),
  129.                "d" (offsetof(struct frame,un)/2-1),
  130.                "g" (offsetof(struct frame,un)), "a" (fp)
  131.              : "a0", "a1", "d0");
  132.         for (;;)
  133.             ;
  134.         /* NOTREACHED */
  135.     }
  136.  
  137.     return regs->d0;
  138. }
  139.  
  140. /*
  141.  * Set up a signal frame...
  142.  *
  143.  * This routine is somewhat complicated by the fact that if the
  144.  * kernel may be entered by an exception other than a system call;
  145.  * e.g. a bus error or other "bad" exception.  If this is the case,
  146.  * then *all* the context on the kernel stack frame must be saved.
  147.  *
  148.  * For a large number of exceptions, the stack frame format is the same
  149.  * as that which will be created when the process traps back to the kernel
  150.  * when finished executing the signal handler.    In this case, nothing
  151.  * must be done.  This is exception frame format "0".  For exception frame
  152.  * formats "2", "9", "A" and "B", the extra information on the frame must
  153.  * be saved.  This information is saved on the user stack and restored
  154.  * when the signal handler is returned.
  155.  *
  156.  * Note that this code must be extended to handle frame formats "3", "4"
  157.  * and "7" to support the 68040.
  158.  *
  159.  * The format of the user stack when executing the signal handler is:
  160.  *
  161.  *     usp ->  RETADDR (points to code below)
  162.  *           signum  (parm #1)
  163.  *           sigcode (parm #2 ; unused)
  164.  *           scp     (parm #3 ; sigcontext pointer, pointer to #1 below)
  165.  *           code1   (addaw #20,sp) ; pop parms and code off stack
  166.  *           code2   (moveq #119,d0; trap #0) ; sigreturn syscall
  167.  *     #1|     oldmask
  168.  *     |     old usp
  169.  *     |     d0      (first saved reg)
  170.  *     |     d1
  171.  *     |     a0
  172.  *     |     a1
  173.  *     |     sr      (saved status register)
  174.  *     |     pc      (old pc; one to return to)
  175.  *     |     forvec  (format and vector word of old supervisor stack frame)
  176.  *
  177.  * These are optionally followed by some extra stuff, depending on the
  178.  * stack frame interrupted. This is 1 longword for format "2", 3
  179.  * longwords for format "9", 6 longwords for format "A", and 21
  180.  * longwords for format "B".
  181.  *
  182.  * XXX This format must be changed to save floating point context also.
  183.  */
  184.  
  185. #define UFRAME_SIZE(fs) (sizeof(struct sigcontext) + 8 + fs/4)
  186.  
  187. static void setup_frame (struct sigaction * sa, unsigned long **fp, unsigned long pc,
  188.              struct frame *regs, int signr, unsigned long oldmask)
  189. {
  190.     struct sigcontext context;
  191.     unsigned long *frame, *tframe;
  192.  
  193.     switch (regs->format) {
  194.         case 0x0:
  195.         frame = *fp - UFRAME_SIZE(0);
  196.         verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(0)*4);
  197.         break;
  198.         case 0x2:
  199.         frame = *fp - UFRAME_SIZE(sizeof(regs->un.fmt2));
  200.         verify_area(VERIFY_WRITE,frame,
  201.                 UFRAME_SIZE(sizeof(regs->un.fmt2))*4);
  202.         put_fs_long(regs->un.fmt2.iaddr, frame+UFRAME_SIZE(0));
  203.         regs->stkadj = sizeof(regs->un.fmt2);
  204.         break;
  205.         case 0x9:
  206.         frame = *fp - UFRAME_SIZE(sizeof(regs->un.fmt9));
  207.         verify_area(VERIFY_WRITE,frame,
  208.                 UFRAME_SIZE(sizeof(regs->un.fmt9))*4);
  209.         memcpy_tofs (frame+UFRAME_SIZE(0), ®s->un.fmt9,
  210.                  sizeof(regs->un.fmt9));
  211.         regs->stkadj = sizeof(regs->un.fmt9);
  212.         break;
  213.         case 0xA:
  214.         frame = *fp - UFRAME_SIZE(sizeof(regs->un.fmta));
  215.         verify_area(VERIFY_WRITE,frame,
  216.                 UFRAME_SIZE(sizeof(regs->un.fmta))*4);
  217.         memcpy_tofs (frame+UFRAME_SIZE(0), ®s->un.fmta,
  218.                  sizeof(regs->un.fmta));
  219.         regs->stkadj = sizeof(regs->un.fmta);
  220.         break;
  221.         case 0xB:
  222.         frame = *fp - UFRAME_SIZE(sizeof(regs->un.fmtb));
  223.         verify_area(VERIFY_WRITE,frame,
  224.                 UFRAME_SIZE(sizeof(regs->un.fmtb))*4);
  225.         memcpy_tofs (frame+UFRAME_SIZE(0), ®s->un.fmtb,
  226.                  sizeof(regs->un.fmtb));
  227.         regs->stkadj = sizeof(regs->un.fmtb);
  228.         break;
  229.         default:
  230.         printk ("setup_frame: Unknown frame format %#x\n",
  231.             regs->format);
  232.         panic ("setup_frame: Unknown frame format");
  233.     }
  234.  
  235. /* set up the "normal" stack seen by the signal handler */
  236.     tframe = frame;
  237.  
  238.     /* return address points to code on stack */
  239.     put_fs_long((ulong)(frame+4), tframe); tframe++;
  240.     put_fs_long(signr, tframe);   tframe++;
  241.     put_fs_long(0, tframe); tframe++;    /* "code" parameter.  Unused */
  242.     /* "scp" parameter.  points to sigcontext */
  243.     put_fs_long((ulong)(frame+6), tframe); tframe++;
  244.  
  245. /* set up the return code... */
  246.     put_fs_long(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
  247.     put_fs_long(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
  248.  
  249. /* Flush caches so the instructions will be correctly executed. (MA) */
  250.     cache_push_v ((unsigned long)frame, (int)tframe - (int)frame);
  251.  
  252. /* setup and copy the sigcontext structure */
  253.     context.sc_mask       = oldmask;
  254.     context.sc_usp          = (unsigned long)*fp;
  255.     context.sc_d0          = regs->d0;
  256.     context.sc_d1          = regs->regs[0];
  257.     context.sc_a0          = regs->regs[7];
  258.     context.sc_a1          = regs->regs[8];
  259.     context.sc_sr          = regs->sr;
  260.     context.sc_pc          = pc;
  261.     context.sc_formatvec  = regs->format << 12 | regs->vector;
  262.     memcpy_tofs (tframe, &context, sizeof(context));
  263.  
  264.     /*
  265.      * no matter what frame format we were using before, we
  266.      * will do the "RTE" using a normal 4 word frame.
  267.      */
  268.     regs->format = 0;
  269.  
  270.     /* "return" new usp to caller */
  271.     *fp = frame;
  272. }
  273.  
  274. /*
  275.  * Note that 'init' is a special process: it doesn't get signals it doesn't
  276.  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  277.  * mistake.
  278.  *
  279.  * Note that we go through the signals twice: once to check the signals
  280.  * that the kernel can handle, and then we build all the user-level signal
  281.  * handling stack-frames in one go after that.
  282.  */
  283. asmlinkage int do_signal(unsigned long oldmask, struct frame * regs)
  284. {
  285.     unsigned long mask = ~current->blocked;
  286.     unsigned long handler_signal = 0;
  287.     unsigned long *frame = NULL;
  288.     unsigned long pc = 0;
  289.     unsigned long signr;
  290.     struct sigaction * sa;
  291.  
  292.     while ((signr = current->signal & mask)) {
  293.         __asm__("bfffo  %2,#0,#0,%1\n\t"
  294.             "bfclr  %0,%1,#1\n\t"
  295.             "negl   %1\n\t"
  296.             "addl   #31,%1"
  297.             :"=m" (current->signal),"=r" (signr)
  298.             :"1" (signr));
  299.         sa = current->sigaction + signr;
  300.         signr++;
  301.  
  302.         if (signr == SIGSEGV)
  303.             printk ("%s: SIGSEGV from pc %#lx, regs=%p\n",
  304.                 current->comm, regs->pc, regs);
  305.  
  306.         if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
  307.             current->exit_code = signr;
  308.             current->state = TASK_STOPPED;
  309.             notify_parent(current);
  310.             schedule();
  311.             if (!(signr = current->exit_code))
  312.                 continue;
  313.             current->exit_code = 0;
  314.             if (signr == SIGSTOP)
  315.                 continue;
  316.             if (_S(signr) & current->blocked) {
  317.                 current->signal |= _S(signr);
  318.                 continue;
  319.             }
  320.             sa = current->sigaction + signr - 1;
  321.         }
  322.         if (sa->sa_handler == SIG_IGN) {
  323.             if (signr != SIGCHLD)
  324.                 continue;
  325.             /* check for SIGCHLD: it's special */
  326.             while (sys_waitpid(-1,NULL,WNOHANG) > 0)
  327.                 /* nothing */;
  328.             continue;
  329.         }
  330.         if (sa->sa_handler == SIG_DFL) {
  331.             if (current->pid == 1)
  332.                 continue;
  333.             switch (signr) {
  334.                 case SIGCONT: case SIGCHLD: case SIGWINCH:
  335.                 continue;
  336.  
  337.                 case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
  338.                 if (current->flags & PF_PTRACED)
  339.                     continue;
  340.                 current->state = TASK_STOPPED;
  341.                 current->exit_code = signr;
  342.                 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
  343.                       SA_NOCLDSTOP))
  344.                     notify_parent(current);
  345.                 schedule();
  346.                 continue;
  347.  
  348.                 case SIGQUIT: case SIGILL: case SIGTRAP:
  349.                 case SIGIOT: case SIGFPE: case SIGSEGV:
  350.                 if (core_dump(signr,(struct pt_regs *)regs))
  351.                     signr |= 0x80;
  352.                 /* fall through */
  353.                 default:
  354.                 current->signal |= _S(signr & 0x7f);
  355.                 do_exit(signr);
  356.             }
  357.         }
  358.         /*
  359.          * OK, we're invoking a handler
  360.          */
  361.         if (regs->orig_d0 >= 0) {
  362.             if (regs->d0 == -ERESTARTNOHAND ||
  363.                 (regs->d0 == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
  364.                 regs->d0 = -EINTR;
  365.         }
  366.         handler_signal |= 1 << (signr-1);
  367.         mask &= ~sa->sa_mask;
  368.     }
  369.     if (regs->orig_d0 >= 0 &&
  370.         (regs->d0 == -ERESTARTNOHAND ||
  371.          regs->d0 == -ERESTARTSYS ||
  372.          regs->d0 == -ERESTARTNOINTR)) {
  373.         regs->d0 = regs->orig_d0;
  374.         regs->pc -= 2;
  375.     }
  376.     if (!handler_signal)    /* no handler will be called - return 0 */
  377.         return 0;
  378.     pc = regs->pc;
  379.     frame = (unsigned long *)regs->usp;
  380.     signr = 1;
  381.     sa = current->sigaction;
  382.     for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
  383.         if (mask > handler_signal)
  384.             break;
  385.         if (!(mask & handler_signal))
  386.             continue;
  387.         setup_frame(sa,&frame,pc,regs,signr,oldmask);
  388.         pc = (unsigned long) sa->sa_handler;
  389.         if (sa->sa_flags & SA_ONESHOT)
  390.             sa->sa_handler = NULL;
  391. /* force a supervisor-mode page-in of the signal handler to reduce races */
  392.         __asm__ __volatile__("movesb %0,d0": :"m" (*(char *)pc):"d0");
  393.         current->blocked |= sa->sa_mask;
  394.         oldmask |= sa->sa_mask;
  395.     }
  396.     regs->usp = (unsigned long) frame;
  397.     regs->pc = pc;
  398.  
  399.     /*
  400.      * if setup_frame saved some extra frame junk, we need to
  401.      * skip over that stuff when doing the RTE.  This means we have
  402.      * to move the machine portion of the stack frame to where the
  403.      * "RTE" instruction expects it. The signal that we need to
  404.      * do this is that regs->stkadj is nonzero.
  405.      */
  406.     if (regs->stkadj) {
  407.         struct frame *tregs =
  408.             (struct frame *)((ulong)regs + regs->stkadj);
  409.  
  410.         tregs->sr = regs->sr;
  411.         tregs->pc = regs->pc;
  412.         tregs->format = regs->format;
  413.         tregs->vector = regs->vector;
  414.     }
  415.  
  416.     return 1;
  417. }
  418.